﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace ICodeShare.UI.Controls
{
    /// <summary>
    /// 自定义控件-测量仪表（Gauge）
    /// </summary>
    [TemplatePart(Name = "LayoutRoot", Type = typeof(Grid))]
    [TemplatePart(Name = "Pointer", Type = typeof(Path))]
    [TemplatePart(Name = "RangeIndicatorLight", Type = typeof(Ellipse))]
    [TemplatePart(Name = "PointerCap", Type = typeof(Ellipse))]
    public class CircularGauge : Control
    {
        #region Members

        private Grid rootGrid;
        private Path rangeIndicator;
        private Path pointer;
        private Ellipse pointerCap;
        private Ellipse lightIndicator;
        private bool isInitialValueSet = false;
        private Double arcradius1;
        private Double arcradius2;
        private int animatingSpeedFactor = 6;

        #endregion Members

        #region 构造函数

        public CircularGauge()
        {
            DefaultStyleKey = typeof(CircularGauge);
        }

        #endregion 构造函数

        #region Dependency Properties

        #region CurrentValue 获取或设置当前属性的值

        /// <summary>
        /// 获取或设置当前属性的值
        /// </summary>
        public double CurrentValue
        {
            get { return (double)GetValue(CurrentValueProperty); }
            set { SetValue(CurrentValueProperty, value); }
        }

        /// <summary>
        /// 获取或设置当前属性的值
        /// </summary>
        public static readonly DependencyProperty CurrentValueProperty =DependencyProperty.Register(
            "CurrentValue", 
            typeof(double), 
            typeof(CircularGauge),
            new PropertyMetadata(0.0, new PropertyChangedCallback(CircularGauge.OnCurrentValuePropertyChanged)));

        #endregion

        #region Radius 获取或设置控件的半径

        /// <summary>
        /// 获取或设置控件的半径
        /// </summary>
        public double Radius
        {
            get { return (double)GetValue(RadiusProperty); }
            set { SetValue(RadiusProperty, value); }
        }

        /// <summary>
        /// 获取或设置仪表半径的值
        /// </summary>
        public static readonly DependencyProperty RadiusProperty =DependencyProperty.Register(
            "Radius", 
            typeof(double), 
            typeof(CircularGauge),
            new PropertyMetadata(100.0));

        #endregion

        #region MinValue 获取或设置刻度值的最小值

        /// <summary>
        /// 获取或设置刻度值的最小值
        /// </summary>
        public double MinValue
        {
            get { return (double)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }

        /// <summary>
        /// 获取或设置当前属性的最小值
        /// </summary>
        public static readonly DependencyProperty MinValueProperty =
              DependencyProperty.Register("MinValue", typeof(double), typeof(CircularGauge), new PropertyMetadata(0.0));

        #endregion

        #region MaxValue 获取或设置刻度值的最大值

        /// <summary>
        /// 获取或设置刻度值的最大值
        /// </summary>
        public double MaxValue
        {
            get { return (double)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        /// <summary>
        /// 获取或设置当前属性的最大值
        /// </summary>
        public static readonly DependencyProperty MaxValueProperty =
               DependencyProperty.Register("MaxValue", typeof(double), typeof(CircularGauge), new PropertyMetadata(100.0));

        #endregion

        #region 指示范围

        #region OptimalRangeStartValue 安全范围最小值

        /// <summary>
        /// 获取或设置主要刻度最小值
        /// </summary>
        public double OptimalRangeStartValue
        {
            get { return (double)GetValue(OptimalRangeStartValueProperty); }
            set { SetValue(OptimalRangeStartValueProperty, value); }
        }


        public static readonly DependencyProperty OptimalRangeStartValueProperty =
            DependencyProperty.Register("OptimalRangeStartValue", typeof(double), typeof(CircularGauge), new PropertyMetadata(30.0, new PropertyChangedCallback(CircularGauge.OnOptimalRangeStartValuePropertyChanged)));

        #endregion

        #region OptimalRangeEndValue 安全范围最大值

        /// <summary>
        /// 获取或设置主要刻度最大值
        /// </summary>
        public double OptimalRangeEndValue
        {
            get { return (double)GetValue(OptimalRangeEndValueProperty); }
            set { SetValue(OptimalRangeEndValueProperty, value); }
        }

        public static readonly DependencyProperty OptimalRangeEndValueProperty =
             DependencyProperty.Register("OptimalRangeEndValue", typeof(double), typeof(CircularGauge), new PropertyMetadata(85.0, new PropertyChangedCallback(CircularGauge.OnOptimalRangeEndValuePropertyChanged)));

        #endregion

        #region RangeIndicatorRadius 指示范围的半径
        /// <summary>
        /// 获取或设置指示范围的半径
        /// </summary>
        public double RangeIndicatorRadius
        {
            get { return (double)GetValue(RangeIndicatorRadiusProperty); }
            set { SetValue(RangeIndicatorRadiusProperty, value); }
        }


        public static readonly DependencyProperty RangeIndicatorRadiusProperty =
           DependencyProperty.Register("RangeIndicatorRadius", typeof(double), typeof(CircularGauge), new PropertyMetadata(98.0));

        #endregion

        #region RangeIndicatorThickness 指示范围的粗度

        /// <summary>
        /// 获取或设置指示范围的粗度
        /// </summary>
        public double RangeIndicatorThickness
        {
            get { return (double)GetValue(RangeIndicatorThicknessProperty); }
            set { SetValue(RangeIndicatorThicknessProperty, value); }
        }
        public static readonly DependencyProperty RangeIndicatorThicknessProperty =
          DependencyProperty.Register("RangeIndicatorThickness", typeof(double), typeof(CircularGauge), new PropertyMetadata(2.0));

        #endregion

        #region BelowOptimalRangeColor 左部条的颜色

        /// <summary>
        /// 设置或获取左部条的颜色
        /// </summary>
        public Color BelowOptimalRangeColor
        {
            get { return (Color)GetValue(BelowOptimalRangeColorProperty); }
            set { SetValue(BelowOptimalRangeColorProperty, value); }
        }

        public static readonly DependencyProperty BelowOptimalRangeColorProperty =
            DependencyProperty.Register("BelowOptimalRangeColor", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.Yellow));

        #endregion

        #region OptimalRangeColor 顶部条的颜色

        /// <summary>
        /// 设置或获取顶部条的颜色
        /// </summary>
        public Color OptimalRangeColor
        {
            get { return (Color)GetValue(OptimalRangeColorProperty); }
            set { SetValue(OptimalRangeColorProperty, value); }
        }

        public static readonly DependencyProperty OptimalRangeColorProperty =
            DependencyProperty.Register("OptimalRangeColor", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.Green));

        #endregion

        #region AboveOptimalRangeColor 右边颜色

        /// <summary>
        /// 获取或设置度右边颜色
        /// </summary>
        public Color AboveOptimalRangeColor
        {
            get { return (Color)GetValue(AboveOptimalRangeColorProperty); }
            set { SetValue(AboveOptimalRangeColorProperty, value); }
        }

        public static readonly DependencyProperty AboveOptimalRangeColorProperty =
            DependencyProperty.Register("AboveOptimalRangeColor", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.Red));

        #endregion

        #endregion

        #region 指针

        #region PointerCapRadius 中心圆的半径

        /// <summary>
        /// 获取或设置中心圆的半径
        /// </summary>
        public double PointerCapRadius
        {
            get { return (double)GetValue(PointerCapRadiusProperty); }
            set { SetValue(PointerCapRadiusProperty, value); }
        }

        /// <summary>
        /// 获取或设置指针半径的值
        /// </summary>
        public static readonly DependencyProperty PointerCapRadiusProperty =
               DependencyProperty.Register("PointerCapRadius", typeof(double), typeof(CircularGauge), new PropertyMetadata(10.0));

        #endregion

        #region PointerThickness 指针的粗度

        /// <summary>
        /// 获取或设置指针的粗度
        /// </summary>
        public double PointerThickness
        {
            get { return (double)GetValue(PointerThicknessProperty); }
            set { SetValue(PointerThicknessProperty, value); }
        }

        public static readonly DependencyProperty PointerThicknessProperty = DependencyProperty.Register(
            "PointerThickness",
            typeof(double),
            typeof(CircularGauge),
            new PropertyMetadata(4.0));

        #endregion

        #region PointerLength 指针长度

        /// <summary>
        /// 获取或设置指针长度
        /// </summary>
        public double PointerLength
        {
            get { return (double)GetValue(PointerLengthProperty); }
            set { SetValue(PointerLengthProperty, value); }
        }

        /// <summary>
        ///  获取或设置指针的长度
        /// </summary>
        public static readonly DependencyProperty PointerLengthProperty =
             DependencyProperty.Register("PointerLength", typeof(double), typeof(CircularGauge), new PropertyMetadata(65.0));

        #endregion

        #region ResetPointerOnStartUp 指针的起始角度

        /// <summary>
        /// 设置或获取指针的起始角度
        /// </summary>
        public bool ResetPointerOnStartUp
        {
            get { return (bool)GetValue(ResetPointerOnStartUpProperty); }
            set { SetValue(ResetPointerOnStartUpProperty, value); }
        }

        public static readonly DependencyProperty ResetPointerOnStartUpProperty =
        DependencyProperty.Register("ResetPointerOnStartUp", typeof(bool), typeof(CircularGauge), new PropertyMetadata(false));

        #endregion

        #endregion

        #region 刻度线

        #region ScaleValuePrecision 刻度的精度

        /// <summary>
        /// 设置或获取刻度的精度
        /// </summary>
        public int ScaleValuePrecision
        {
            get { return (int)GetValue(ScaleValuePrecisionProperty); }
            set { SetValue(ScaleValuePrecisionProperty, value); }
        }

        public static readonly DependencyProperty ScaleValuePrecisionProperty =
               DependencyProperty.Register("ScaleValuePrecision", typeof(int), typeof(CircularGauge), new PropertyMetadata(2));

        #endregion

        #region 主要刻度线

        #region ScaleRadius 刻度的半径

        /// <summary>
        /// 获取或设置刻度的半径
        /// </summary>
        public double ScaleRadius
        {
            get { return (double)GetValue(ScaleRadiusProperty); }
            set { SetValue(ScaleRadiusProperty, value); }
        }

        /// <summary>
        /// 获取或设置刻度的半径
        /// </summary>
        public static readonly DependencyProperty ScaleRadiusProperty =
             DependencyProperty.Register("ScaleRadius", typeof(double), typeof(CircularGauge), new PropertyMetadata(95.0));

        #endregion

        #region ScaleStartAngle 刻度的起始角度

        /// <summary>
        /// 获取或设置刻度的起始角度
        /// </summary>
        public double ScaleStartAngle
        {
            get { return (double)GetValue(ScaleStartAngleProperty); }
            set { SetValue(ScaleStartAngleProperty, value); }
        }

        /// <summary>
        /// 获取或设置刻度的起始角度
        /// </summary>
        public static readonly DependencyProperty ScaleStartAngleProperty =
              DependencyProperty.Register("ScaleStartAngle", typeof(double), typeof(CircularGauge), new PropertyMetadata(-240.0));

        #endregion

        #region ScaleSweepAngle 刻度的摆动角度

        /// <summary>
        /// 获取或设置刻度的摆动角度
        /// </summary>
        public double ScaleSweepAngle
        {
            get { return (double)GetValue(ScaleSweepAngleProperty); }
            set { SetValue(ScaleSweepAngleProperty, value); }
        }

        public static readonly DependencyProperty ScaleSweepAngleProperty =
             DependencyProperty.Register("ScaleSweepAngle", typeof(double), typeof(CircularGauge), new PropertyMetadata(300.0));

        #endregion

        #region MajorDivisionsCount 主要刻度点个数

        /// <summary>
        /// 获取或设置主要刻度点个数
        /// </summary>
        public double MajorDivisionsCount
        {
            get { return (double)GetValue(MajorDivisionsCountProperty); }
            set { SetValue(MajorDivisionsCountProperty, value); }
        }

        public static readonly DependencyProperty MajorDivisionsCountProperty =
             DependencyProperty.Register("MajorDivisionsCount", typeof(double), typeof(CircularGauge), new PropertyMetadata(10.0));

        #endregion

        #region MajorTickSize 主要刻度线的的长度

        /// <summary>
        /// 设置或获取主要刻度线的的长度
        /// </summary>
        public Size MajorTickSize
        {
            get { return (Size)GetValue(MajorTickSizeProperty); }
            set { SetValue(MajorTickSizeProperty, value); }
        }

        public static readonly DependencyProperty MajorTickSizeProperty =
           DependencyProperty.Register("MajorTickSize", typeof(Size), typeof(CircularGauge), new PropertyMetadata(new Size(10,2)));

        #endregion

        #region MajorTickColor 主要刻度线的颜色

        /// <summary>
        /// 设置或获取主要刻度线的颜色
        /// </summary>
        public Color MajorTickColor
        {
            get { return (Color)GetValue(MajorTickColorProperty); }
            set { SetValue(MajorTickColorProperty, value); }
        }

        public static readonly DependencyProperty MajorTickColorProperty =
            DependencyProperty.Register("MajorTickColor", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.LightGray));

        #endregion

        #endregion

        #region 辅助刻度线

        #region MinorDivisionsCount 辅助刻度点个数

        /// <summary>
        /// 获取或设置辅助刻度点个数
        /// </summary>
        public double MinorDivisionsCount
        {
            get { return (double)GetValue(MinorDivisionsCountProperty); }
            set { SetValue(MinorDivisionsCountProperty, value); }
        }

        public static readonly DependencyProperty MinorDivisionsCountProperty =
             DependencyProperty.Register("MinorDivisionsCount", typeof(double), typeof(CircularGauge), new PropertyMetadata(5.0));

        #endregion

        #region MinorTickSize 辅助刻度线的长度

        /// <summary>
        /// 设置或获取辅助刻度线的长度
        /// </summary>
        public Size MinorTickSize
        {
            get { return (Size)GetValue(MinorTickSizeProperty); }
            set { SetValue(MinorTickSizeProperty, value); }
        }

        public static readonly DependencyProperty MinorTickSizeProperty =
         DependencyProperty.Register("MinorTickSize", typeof(Size), typeof(CircularGauge), new PropertyMetadata(new Size(5, 1)));

        #endregion

        #region MinorTickColor 辅助刻度线的颜色

        /// <summary>
        /// 设置或获取辅助刻度线的颜色
        /// </summary>
        public Color MinorTickColor
        {
            get { return (Color)GetValue(MinorTickColorProperty); }
            set { SetValue(MinorTickColorProperty, value); }
        }

        public static readonly DependencyProperty MinorTickColorProperty =
          DependencyProperty.Register("MinorTickColor", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.LightGray));

        #endregion

        #endregion

        #region 刻度文本

        #region ScaleLabelRadius 刻度文本半径
        /// <summary>
        /// 获取或设置刻度文本半径
        /// </summary>
        public double ScaleLabelRadius
        {
            get { return (double)GetValue(ScaleLabelRadiusProperty); }
            set { SetValue(ScaleLabelRadiusProperty, value); }
        }

        public static readonly DependencyProperty ScaleLabelRadiusProperty =
             DependencyProperty.Register("ScaleLabelRadius", typeof(double), typeof(CircularGauge), new PropertyMetadata(82.0));

        #endregion

        #region ScaleLabelSize 刻度文本的大小

        /// <summary>
        /// 设置或获取刻度文本的大小
        /// </summary>
        public Size ScaleLabelSize
        {
            get { return (Size)GetValue(ScaleLabelSizeProperty); }
            set { SetValue(ScaleLabelSizeProperty, value); }
        }

        public static readonly DependencyProperty ScaleLabelSizeProperty =
          DependencyProperty.Register("ScaleLabelSize", typeof(Size), typeof(CircularGauge), new PropertyMetadata(new Size(40, 20)));

        #endregion

        #region ScaleLabelFontSize 刻度文本的字体大小

        /// <summary>
        /// 设置或获取刻度文本的字体大小
        /// </summary>
        public double ScaleLabelFontSize
        {
            get { return (double)GetValue(ScaleLabelFontSizeProperty); }
            set { SetValue(ScaleLabelFontSizeProperty, value); }
        }

        public static readonly DependencyProperty ScaleLabelFontSizeProperty =
             DependencyProperty.Register("ScaleLabelFontSize", typeof(double), typeof(CircularGauge), new PropertyMetadata(10.0));

        #endregion

        #region ScaleLabelForeground 刻度文本字体颜色

        /// <summary>
        /// 设置或获取仪表的刻度文本的前景色
        /// </summary>
        public Color ScaleLabelForeground
        {
            get { return (Color)GetValue(ScaleLabelForegroundProperty); }
            set { SetValue(ScaleLabelForegroundProperty, value); }
        }

        public static readonly DependencyProperty ScaleLabelForegroundProperty =
             DependencyProperty.Register("ScaleLabelForeground", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.LightGray));

        #endregion

        #endregion

        #endregion

        #region 图标

        #region ImageSource 图片地址

        /// <summary>
        /// /// <summary>
        /// 获取或设置图片地址
        /// </summary>
        /// </summary>
        public ImageSource ImageSource
        {
            get { return (ImageSource)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }

        public static readonly DependencyProperty ImageSourceProperty =
           DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(CircularGauge), null);

        #endregion

        #region ImageOffset 控件的相对于中心点的图片位置

        /// <summary>
        /// /// <summary>
        /// 获取或设置控件的相对于中心点的图片位置
        /// </summary>
        /// </summary>
        public double ImageOffset
        {
            get { return (double)GetValue(ImageOffsetProperty); }
            set { SetValue(ImageOffsetProperty, value); }
        }

        public static readonly DependencyProperty ImageOffsetProperty =
           DependencyProperty.Register("ImageOffset", typeof(double), typeof(CircularGauge), new PropertyMetadata(-30.0));

        #endregion

        #region ImageSize 图片的大小

        /// <summary>
        ///  获取或设置图片的大小
        /// </summary>
        public Size ImageSize
        {
            get { return (Size)GetValue(ImageSizeProperty); }
            set { SetValue(ImageSizeProperty, value); }
        }

        public static readonly DependencyProperty ImageSizeProperty =
          DependencyProperty.Register("ImageSize", typeof(Size), typeof(CircularGauge), new PropertyMetadata(new Size(60, 50)));

        #endregion

        #endregion

        #region 指示灯

        #region RangeIndicatorLightOffset 指示灯相对于控件中心点位置

        /// <summary>
        ///  获取或设置指示灯相对于控件中心点位置
        /// </summary>
        public double RangeIndicatorLightOffset
        {
            get { return (double)GetValue(RangeIndicatorLightOffsetProperty); }
            set { SetValue(RangeIndicatorLightOffsetProperty, value); }
        }

        public static readonly DependencyProperty RangeIndicatorLightOffsetProperty =
          DependencyProperty.Register("RangeIndicatorLightOffset", typeof(double), typeof(CircularGauge), new PropertyMetadata(55.0));
        #endregion

        #region RangeIndicatorLightRadius 指示灯的半径

        /// <summary>
        /// 获取或设置指示灯的半径
        /// </summary>
        public double RangeIndicatorLightRadius
        {
            get { return (double)GetValue(RangeIndicatorLightRadiusProperty); }
            set { SetValue(RangeIndicatorLightRadiusProperty, value); }
        }

        public static readonly DependencyProperty RangeIndicatorLightRadiusProperty =
            DependencyProperty.Register("RangeIndicatorLightRadius", typeof(double), typeof(CircularGauge), new PropertyMetadata(5.0));

        #endregion

        #endregion

        #region 标题文本

        #region DialText 文本

        /// <summary>
        /// 获取或设置文本
        /// </summary>
        public string DialText
        {
            get { return (string)GetValue(DialTextProperty); }
            set { SetValue(DialTextProperty, value); }
        }

        public static readonly DependencyProperty DialTextProperty =
            DependencyProperty.Register("DialText", typeof(string), typeof(CircularGauge), new PropertyMetadata(""));

        #endregion

        #region DialTextColor 文本颜色

        /// <summary>
        /// 获取或设置文本颜色
        /// </summary>
        public Color DialTextColor
        {
            get { return (Color)GetValue(DialTextColorProperty); }
            set { SetValue(DialTextColorProperty, value); }
        }

        public static readonly DependencyProperty DialTextColorProperty =
            DependencyProperty.Register("DialTextColor", typeof(Color), typeof(CircularGauge), new PropertyMetadata(Colors.AliceBlue));

        #endregion

        #region DialTextFontSize 文本字体的大小


        /// <summary>
        /// 获取或设置文本字体的大小
        /// </summary>
        public int DialTextFontSize
        {
            get { return (int)GetValue(DialTextFontSizeProperty); }
            set { SetValue(DialTextFontSizeProperty, value); }
        }

        public static readonly DependencyProperty DialTextFontSizeProperty =
            DependencyProperty.Register("DialTextFontSize", typeof(int), typeof(CircularGauge), new PropertyMetadata(8));

        #endregion

        #region DialTextOffset 文本相对于控件中心点位置

        /// <summary>
        /// 获取或设置文本位置
        /// </summary>
        public double DialTextOffset
        {
            get { return (double)GetValue(DialTextOffsetProperty); }
            set { SetValue(DialTextOffsetProperty, value); }
        }

        public static readonly DependencyProperty DialTextOffsetProperty =
            DependencyProperty.Register("DialTextOffset", typeof(double), typeof(CircularGauge), new PropertyMetadata(70.0));

        #endregion

        #endregion

        #endregion Dependency Properties

        #region 私有方法

        private static void OnCurrentValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CircularGauge gauge = d as CircularGauge;
            gauge.OnCurrentValueChanged(e);
        }

        private static void OnOptimalRangeEndValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CircularGauge gauge = d as CircularGauge;
            if ((double)e.NewValue > gauge.MaxValue)
            {
                gauge.OptimalRangeEndValue = gauge.MaxValue;
            }
        }

        private static void OnOptimalRangeStartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CircularGauge gauge = d as CircularGauge;
            if ((double)e.NewValue < gauge.MinValue)
            {
                gauge.OptimalRangeStartValue = gauge.MinValue;
            }
        }

        public virtual void OnCurrentValueChanged(DependencyPropertyChangedEventArgs e)
        {
            double newValue = (double)e.NewValue;
            double oldValue = (double)e.OldValue;
            if (newValue > this.MaxValue)
            {
                newValue = this.MaxValue;
            }
            else if (newValue < this.MinValue)
            {
                newValue = this.MinValue;
            }

            if (oldValue > this.MaxValue)
            {
                oldValue = this.MaxValue;
            }
            else if (oldValue < this.MinValue)
            {
                oldValue = this.MinValue;
            }
            if (pointer != null)
            {
                double db1 = 0;
                Double oldcurr_realworldunit = 0;
                Double newcurr_realworldunit = 0;
                Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
                //Resetting the old value to min value the very first time.
                if (oldValue == 0 && !isInitialValueSet)
                {
                    oldValue = MinValue;
                    isInitialValueSet = true;
                }
                if (oldValue < 0)
                {
                    db1 = MinValue + Math.Abs(oldValue);
                    oldcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
                }
                else
                {
                    db1 = Math.Abs(MinValue) + oldValue;
                    oldcurr_realworldunit = ((double)(db1 * realworldunit));
                }
                if (newValue < 0)
                {
                    db1 = MinValue + Math.Abs(newValue);
                    newcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
                }
                else
                {
                    db1 = Math.Abs(MinValue) + newValue;
                    newcurr_realworldunit = ((double)(db1 * realworldunit));
                }

                Double oldcurrentvalueAngle = (ScaleStartAngle + oldcurr_realworldunit);
                Double newcurrentvalueAngle = (ScaleStartAngle + newcurr_realworldunit);

                //Animate the pointer from the old value to the new value
                AnimatePointer(oldcurrentvalueAngle, newcurrentvalueAngle);
            }
        }

        private void AnimatePointer(double oldcurrentvalueAngle, double newcurrentvalueAngle)
        {
            if (pointer != null)
            {
                DoubleAnimation da = new DoubleAnimation();
                da.From = oldcurrentvalueAngle;
                da.To = newcurrentvalueAngle;
                double animDuration = Math.Abs(oldcurrentvalueAngle - newcurrentvalueAngle) * animatingSpeedFactor;
                da.Duration = new Duration(TimeSpan.FromMilliseconds(animDuration));

                Storyboard sb = new Storyboard();
                sb.Completed += new EventHandler(sb_Completed);
                sb.Children.Add(da);
                Storyboard.SetTarget(da, pointer);
                Storyboard.SetTargetProperty(da, new PropertyPath("(Path.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
                if (newcurrentvalueAngle != oldcurrentvalueAngle)
                {
                    sb.Begin();
                }
            }
        }

        private void MovePointer(double angleValue)
        {
            if (pointer != null)
            {
                TransformGroup tg = pointer.RenderTransform as TransformGroup;
                RotateTransform rt = tg.Children[0] as RotateTransform;
                rt.Angle = angleValue;
            }
        }

        private void sb_Completed(object sender, EventArgs e)
        {
            if (this.CurrentValue > OptimalRangeEndValue)
            {
                lightIndicator.Fill = GetRangeIndicatorGradEffect(AboveOptimalRangeColor);
            }
            else if (this.CurrentValue <= OptimalRangeEndValue && this.CurrentValue >= OptimalRangeStartValue)
            {
                lightIndicator.Fill = GetRangeIndicatorGradEffect(OptimalRangeColor);
            }
            else if (this.CurrentValue < OptimalRangeStartValue)
            {
                lightIndicator.Fill = GetRangeIndicatorGradEffect(BelowOptimalRangeColor);
            }
        }

        private GradientBrush GetRangeIndicatorGradEffect(Color gradientColor)
        {
            LinearGradientBrush gradient = new LinearGradientBrush();
            gradient.StartPoint = new Point(0, 0);
            gradient.EndPoint = new Point(1, 1);
            GradientStop color1 = new GradientStop();
            if (gradientColor == Colors.Transparent)
            {
                color1.Color = gradientColor;
            }
            else
                color1.Color = Colors.LightGray;

            color1.Offset = 0.2;
            gradient.GradientStops.Add(color1);
            GradientStop color2 = new GradientStop();
            color2.Color = gradientColor; color2.Offset = 0.5;
            gradient.GradientStops.Add(color2);
            GradientStop color3 = new GradientStop();
            color3.Color = gradientColor; color3.Offset = 0.8;
            gradient.GradientStops.Add(color3);
            return gradient;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            //Get reference to known elements on the control template
            rootGrid = GetTemplateChild("LayoutRoot") as Grid;
            pointer = GetTemplateChild("Pointer") as Path;
            pointerCap = GetTemplateChild("PointerCap") as Ellipse;
            lightIndicator = GetTemplateChild("RangeIndicatorLight") as Ellipse;

            //Draw scale and range indicator
            DrawScale();
            DrawRangeIndicator();

            //Set Zindex of pointer and pointer cap to a really high number so that it stays on top of the
            //scale and the range indicator
            Canvas.SetZIndex(pointer, 100000);
            Canvas.SetZIndex(pointerCap, 100001);

            if (ResetPointerOnStartUp)
            {
                //Reset Pointer
                MovePointer(ScaleStartAngle);
            }
        }

        //Drawing the scale with the Scale Radius
        private void DrawScale()
        {
            //Calculate one major tick angle
            Double majorTickUnitAngle = ScaleSweepAngle / MajorDivisionsCount;

            //Obtaining One minor tick angle
            Double minorTickUnitAngle = ScaleSweepAngle / MinorDivisionsCount;

            //Obtaining One major ticks value
            Double majorTicksUnitValue = (MaxValue - MinValue) / MajorDivisionsCount;
            majorTicksUnitValue = Math.Round(majorTicksUnitValue, ScaleValuePrecision);

            Double minvalue = MinValue; ;

            // Drawing Major scale ticks
            for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle)
            {
                //Majortick is drawn as a rectangle
                Rectangle majortickrect = new Rectangle();
                majortickrect.Height = MajorTickSize.Height;
                majortickrect.Width = MajorTickSize.Width;
                majortickrect.Fill = new SolidColorBrush(MajorTickColor);
                Point p = new Point(0.5, 0.5);
                majortickrect.RenderTransformOrigin = p;
                majortickrect.HorizontalAlignment = HorizontalAlignment.Center;
                majortickrect.VerticalAlignment = VerticalAlignment.Center;

                TransformGroup majortickgp = new TransformGroup();
                RotateTransform majortickrt = new RotateTransform();

                //Obtaining the angle in radians for calulating the points
                Double i_radian = (i * Math.PI) / 180;
                majortickrt.Angle = i;
                majortickgp.Children.Add(majortickrt);
                TranslateTransform majorticktt = new TranslateTransform();

                //Finding the point on the Scale where the major ticks are drawn
                //here drawing the points with center as (0,0)
                majorticktt.X = (int)((ScaleRadius) * Math.Cos(i_radian));
                majorticktt.Y = (int)((ScaleRadius) * Math.Sin(i_radian));

                //Points for the textblock which hold the scale value
                TranslateTransform majorscalevaluett = new TranslateTransform();
                //here drawing the points with center as (0,0)
                majorscalevaluett.X = (int)((ScaleLabelRadius) * Math.Cos(i_radian));
                majorscalevaluett.Y = (int)((ScaleLabelRadius) * Math.Sin(i_radian)) + ScaleLabelFontSize / 2;

                //Defining the properties of the scale value textbox
                TextBlock tb = new TextBlock();

                tb.Height = ScaleLabelSize.Height;
                tb.Width = ScaleLabelSize.Width;
                tb.FontSize = ScaleLabelFontSize;
                tb.Foreground = new SolidColorBrush(ScaleLabelForeground);
                tb.TextAlignment = TextAlignment.Center;
                tb.VerticalAlignment = VerticalAlignment.Center;
                tb.HorizontalAlignment = HorizontalAlignment.Center;

                //Writing and appending the scale value

                //checking minvalue < maxvalue w.r.t scale precion value
                if (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision))
                {
                    minvalue = Math.Round(minvalue, ScaleValuePrecision);
                    tb.Text = minvalue.ToString();
                    minvalue = minvalue + majorTicksUnitValue;
                }
                else
                {
                    break;
                }
                majortickgp.Children.Add(majorticktt);
                majortickrect.RenderTransform = majortickgp;
                tb.RenderTransform = majorscalevaluett;
                rootGrid.Children.Add(majortickrect);
                rootGrid.Children.Add(tb);

                //Drawing the minor axis ticks
                Double onedegree = ((i + majorTickUnitAngle) - i) / (MinorDivisionsCount);

                if ((i < (ScaleStartAngle + ScaleSweepAngle)) && (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision)))
                {
                    //Drawing the minor scale
                    for (Double mi = i + onedegree; mi < (i + majorTickUnitAngle); mi = mi + onedegree)
                    {
                        //here the minortick is drawn as a rectangle
                        Rectangle mr = new Rectangle();
                        mr.Height = MinorTickSize.Height;
                        mr.Width = MinorTickSize.Width;
                        mr.Fill = new SolidColorBrush(MinorTickColor);
                        mr.HorizontalAlignment = HorizontalAlignment.Center;
                        mr.VerticalAlignment = VerticalAlignment.Center;
                        Point p1 = new Point(0.5, 0.5);
                        mr.RenderTransformOrigin = p1;

                        TransformGroup minortickgp = new TransformGroup();
                        RotateTransform minortickrt = new RotateTransform();
                        minortickrt.Angle = mi;
                        minortickgp.Children.Add(minortickrt);
                        TranslateTransform minorticktt = new TranslateTransform();

                        //Obtaining the angle in radians for calulating the points
                        Double mi_radian = (mi * Math.PI) / 180;
                        //Finding the point on the Scale where the minor ticks are drawn
                        minorticktt.X = (int)((ScaleRadius) * Math.Cos(mi_radian));
                        minorticktt.Y = (int)((ScaleRadius) * Math.Sin(mi_radian));

                        minortickgp.Children.Add(minorticktt);
                        mr.RenderTransform = minortickgp;
                        rootGrid.Children.Add(mr);
                    }
                }
            }
        }

        /// <summary>
        /// Obtaining the Point (x,y) in the circumference
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        private Point GetCircumferencePoint(Double angle, Double radius)
        {
            Double angle_radian = (angle * Math.PI) / 180;
            //Radius-- is the Radius of the gauge
            Double X = (Double)((Radius) + (radius) * Math.Cos(angle_radian));
            Double Y = (Double)((Radius) + (radius) * Math.Sin(angle_radian));
            Point p = new Point(X, Y);
            return p;
        }

        /// <summary>
        /// Draw the range indicator
        /// </summary>
        private void DrawRangeIndicator()
        {
            Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
            Double optimalStartAngle;
            Double optimalEndAngle;
            double db;

            //Checking whether the  OptimalRangeStartvalue is -ve
            if (OptimalRangeStartValue < 0)
            {
                db = MinValue + Math.Abs(OptimalRangeStartValue);
                optimalStartAngle = ((double)(Math.Abs(db * realworldunit)));
            }
            else
            {
                db = Math.Abs(MinValue) + OptimalRangeStartValue;
                optimalStartAngle = ((double)(db * realworldunit));
            }

            //Checking whether the  OptimalRangeEndvalue is -ve
            if (OptimalRangeEndValue < 0)
            {
                db = MinValue + Math.Abs(OptimalRangeEndValue);
                optimalEndAngle = ((double)(Math.Abs(db * realworldunit)));
            }
            else
            {
                db = Math.Abs(MinValue) + OptimalRangeEndValue;
                optimalEndAngle = ((double)(db * realworldunit));
            }
            // calculating the angle for optimal Start value

            Double optimalStartAngleFromStart = (ScaleStartAngle + optimalStartAngle);

            // calculating the angle for optimal Start value
            Double optimalEndAngleFromStart = (ScaleStartAngle + optimalEndAngle);

            //Calculating the Radius of the two arc for segment
            arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
            arcradius2 = RangeIndicatorRadius;

            double endAngle = ScaleStartAngle + ScaleSweepAngle;
            // Calculating the Points for the below Optimal Range segment from the center of the gauge

            Point A = GetCircumferencePoint(ScaleStartAngle, arcradius1);
            Point B = GetCircumferencePoint(ScaleStartAngle, arcradius2);
            Point C = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
            Point D = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);

            bool isReflexAngle = Math.Abs(optimalStartAngleFromStart - ScaleStartAngle) > 180.0;
            DrawSegment(A, B, C, D, isReflexAngle, BelowOptimalRangeColor);             // Calculating the Points for the Optimal Range segment from the center of the gauge

            Point A1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
            Point B1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
            Point C1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
            Point D1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
            bool isReflexAngle1 = Math.Abs(optimalEndAngleFromStart - optimalStartAngleFromStart) > 180.0;
            DrawSegment(A1, B1, C1, D1, isReflexAngle1, OptimalRangeColor);

            // Calculating the Points for the Above Optimal Range segment from the center of the gauge

            Point A2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
            Point B2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
            Point C2 = GetCircumferencePoint(endAngle, arcradius2);
            Point D2 = GetCircumferencePoint(endAngle, arcradius1);
            bool isReflexAngle2 = Math.Abs(endAngle - optimalEndAngleFromStart) > 180.0;
            DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor);
        }

        //Drawing the segment with two arc and two line

        private void DrawSegment(Point p1, Point p2, Point p3, Point p4, bool reflexangle, Color clr)
        {
            // Segment Geometry
            PathSegmentCollection segments = new PathSegmentCollection();

            // First line segment from pt p1 - pt p2
            segments.Add(new LineSegment() { Point = p2 });

            //Arc drawn from pt p2 - pt p3 with the RangeIndicatorRadius
            segments.Add(new ArcSegment()
            {
                Size = new Size(arcradius2, arcradius2),
                Point = p3,
                SweepDirection = SweepDirection.Clockwise,
                IsLargeArc = reflexangle
            });

            // Second line segment from pt p3 - pt p4
            segments.Add(new LineSegment() { Point = p4 });

            //Arc drawn from pt p4 - pt p1 with the Radius of arcradius1
            segments.Add(new ArcSegment()
            {
                Size = new Size(arcradius1, arcradius1),
                Point = p1,
                SweepDirection = SweepDirection.Counterclockwise,
                IsLargeArc = reflexangle
            });

            // Defining the segment path properties
            Color rangestrokecolor;
            if (clr == Colors.Transparent)
            {
                rangestrokecolor = clr;
            }
            else
                rangestrokecolor = Colors.White;

            rangeIndicator = new Path()
            {
                StrokeLineJoin = PenLineJoin.Round,
                Stroke = new SolidColorBrush(rangestrokecolor),
                //Color.FromArgb(0xFF, 0xF5, 0x9A, 0x86)
                Fill = new SolidColorBrush(clr),
                Opacity = 0.65,
                StrokeThickness = 0.25,
                Data = new PathGeometry()
                {
                    Figures = new PathFigureCollection()
                      {
                         new PathFigure()
                         {
                             IsClosed = true,
                             StartPoint = p1,
                             Segments = segments
                         }
                     }
                }
            };

            //Set Z index of range indicator
            rangeIndicator.SetValue(Canvas.ZIndexProperty, 150);
            // Adding the segment to the root grid
            rootGrid.Children.Add(rangeIndicator);
        }

        #endregion 私有方法
    }
}